package com.lam.framework.security;

import javax.validation.ConstraintViolationException;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.core.AuthenticationException;
import org.springframework.validation.BindException;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.servlet.NoHandlerFoundException;

import com.lam.common.base.domain.Result;
import com.lam.common.constant.HttpStatus;
import com.lam.common.exception.BaseException;
import com.lam.common.exception.BusinessException;
import com.lam.common.exception.ParameterErrorException;
import com.lam.common.utils.CollectionUtil;

/**
 * 全局异常处理器
 * 
 * @author lam
 */
@RestControllerAdvice
public class GlobalExceptionHandler {
	
	private static final Logger log = LoggerFactory.getLogger(GlobalExceptionHandler.class);

	@ExceptionHandler(Throwable.class)
	public Result handleException(Throwable e) {
		
		if(isFailException(e)) {
			//常规的业务失败异常，直接打印异常message，无需打印异常栈
			log.error(e.getMessage());
		}else {
			log.error(e.getMessage(), e);
		}
		return wrapResult(e);
	}
	
	/**
	 * 是否是常规的业务失败异常
	 * @param e
	 * @return
	 */
	public static boolean isFailException(Throwable e) {
		return e instanceof BaseException || e instanceof MethodArgumentNotValidException || e instanceof AccessDeniedException;
	}
	
	/**
	 * 将异常包装转换成返回结果对象
	 * @param e
	 * @return
	 */
	public static Result wrapResult(Throwable e) {
		if(e instanceof ParameterErrorException) {//参数错误异常
			ParameterErrorException ep = (ParameterErrorException)e;
			return Result.fail("参数错误：" + e.getMessage()).code(ep.getCode());
		}
		
		if(e instanceof BusinessException) {//业务错误异常
			BusinessException ep = (BusinessException)e;
			return Result.fail(e.getMessage()).code(ep.getCode());
		}
		
		if(e instanceof BaseException) {//基础异常
			BaseException ep = (BaseException)e;
			return Result.fail("操作失败："+e.getMessage()).code(ep.getCode());
		}
		
		if(e instanceof ConstraintViolationException) {//参数校验失败异常
			ConstraintViolationException ep = (ConstraintViolationException)e;
			return Result.fail(CollectionUtil.getFirst(ep.getConstraintViolations()).getMessage());
		}
		if(e instanceof MethodArgumentNotValidException) {//参数校验失败异常
			MethodArgumentNotValidException ep = (MethodArgumentNotValidException)e;
			return Result.fail(ep.getBindingResult().getAllErrors().get(0).getDefaultMessage());
		}
		if(e instanceof BindException) {//参数绑定异常
			BindException ep = (BindException)e;
			return Result.fail(ep.getAllErrors().get(0).getDefaultMessage());
		}
		
		if(e instanceof HttpRequestMethodNotSupportedException) {//请求方法不支持异常
			return Result.fail("不支持的请求方法").code(HttpStatus.BAD_METHOD);
		}
		if(e instanceof NoHandlerFoundException) {//路径不存在异常
			return Result.fail("路径不存在，请检查路径是否正确").code(HttpStatus.NOT_FOUND);
		}
		if(e instanceof AccessDeniedException) {//没有权限异常
			return Result.fail("没有权限，请联系管理员授权").code(HttpStatus.FORBIDDEN);
		}
		if(e instanceof AuthenticationException) {//身份认证失败异常
			return Result.fail(e.getMessage()).code(HttpStatus.UNAUTHORIZED);
		}
		if(e instanceof MissingServletRequestParameterException) {//参数缺失异常
			MissingServletRequestParameterException ep = (MissingServletRequestParameterException)e;
			return Result.fail(String.format("缺失参数：%s！", ep.getParameterName()));
		}
		
		return Result.fail("系统异常");
	}
}
